# -*- coding: utf-8 -*-
import sys
from requests_toolbelt import MultipartEncoder
import urllib
import os
import subprocess
import hashlib
import random
import requests
from urllib.parse import quote
import json
import time
import re
from googletrans import Translator as tr
from tinytag import TinyTag
# import winreg
import audioop
import math
import multiprocessing
import pysrt
import six
import tempfile
import wave
from googleapiclient.discovery import build
from progressbar import ProgressBar, Percentage, Bar, ETA
import datetime
from textblob import TextBlob




googlekey = 'AIzaSyBOti4mM-6x9WDnZIjIeyEU21OpBXqWBgw'
GOOGLE_SPEECH_API_KEY = googlekey
GOOGLE_SPEECH_API_URL = "http://www.google.com/speech-api/v2/recognize?client=chromium&lang={lang}&key={key}"

LANGUAGE_CODES = {
    'af': 'Afrikaans',
    'ar': 'Arabic',
    'az': 'Azerbaijani',
    'be': 'Belarusian',
    'bg': 'Bulgarian',
    'bn': 'Bengali',
    'bs': 'Bosnian',
    'ca': 'Catalan',
    'ceb': 'Cebuano',
    'cs': 'Czech',
    'cy': 'Welsh',
    'da': 'Danish',
    'de': 'German',
    'el': 'Greek',
    'en': 'English',
    'eo': 'Esperanto',
    'es': 'Spanish',
    'et': 'Estonian',
    'eu': 'Basque',
    'fa': 'Persian',
    'fi': 'Finnish',
    'fr': 'French',
    'ga': 'Irish',
    'gl': 'Galician',
    'gu': 'Gujarati',
    'ha': 'Hausa',
    'hi': 'Hindi',
    'hmn': 'Hmong',
    'hr': 'Croatian',
    'ht': 'Haitian Creole',
    'hu': 'Hungarian',
    'hy': 'Armenian',
    'id': 'Indonesian',
    'ig': 'Igbo',
    'is': 'Icelandic',
    'it': 'Italian',
    'iw': 'Hebrew',
    'ja': 'Japanese',
    'jw': 'Javanese',
    'ka': 'Georgian',
    'kk': 'Kazakh',
    'km': 'Khmer',
    'kn': 'Kannada',
    'ko': 'Korean',
    'la': 'Latin',
    'lo': 'Lao',
    'lt': 'Lithuanian',
    'lv': 'Latvian',
    'mg': 'Malagasy',
    'mi': 'Maori',
    'mk': 'Macedonian',
    'ml': 'Malayalam',
    'mn': 'Mongolian',
    'mr': 'Marathi',
    'ms': 'Malay',
    'mt': 'Maltese',
    'my': 'Myanmar (Burmese)',
    'ne': 'Nepali',
    'nl': 'Dutch',
    'no': 'Norwegian',
    'ny': 'Chichewa',
    'pa': 'Punjabi',
    'pl': 'Polish',
    'pt': 'Portuguese',
    'ro': 'Romanian',
    'ru': 'Russian',
    'si': 'Sinhala',
    'sk': 'Slovak',
    'sl': 'Slovenian',
    'so': 'Somali',
    'sq': 'Albanian',
    'sr': 'Serbian',
    'st': 'Sesotho',
    'su': 'Sudanese',
    'sv': 'Swedish',
    'sw': 'Swahili',
    'ta': 'Tamil',
    'te': 'Telugu',
    'tg': 'Tajik',
    'th': 'Thai',
    'tl': 'Filipino',
    'tr': 'Turkish',
    'uk': 'Ukrainian',
    'ur': 'Urdu',
    'uz': 'Uzbek',
    'vi': 'Vietnamese',
    'yi': 'Yiddish',
    'yo': 'Yoruba',
    'zh-CN': 'Chinese (Simplified)',
    'zh-TW': 'Chinese (Traditional)',
    'zu': 'Zulu',
}


 # TextBlob自然语言处理
def textTrans(text):
    chinese_blob = TextBlob(text)
    transText=chinese_blob.translate(from_lang="en", to="zh-CN")
    return transText

# ------------------------------------------



GOOGLE_SPEECH_API_KEY = googlekey
GOOGLE_SPEECH_API_URL = "http://www.google.com/speech-api/v2/recognize?client=chromium&lang={lang}&key={key}"
# --------------------------------------------
# srt字幕格式化
def srt_formatter(subtitles, padding_before=0, padding_after=0):
    """
    Serialize a list of subtitles according to the SRT format, with optional time padding.
    """
    # 根据SRT格式序列化字幕列表，并带有可选的时间填充

    sub_rip_file = pysrt.SubRipFile()
    for i, ((start, end), text) in enumerate(subtitles, start=1):
        item = pysrt.SubRipItem()
        item.index = i
        item.text = six.text_type(text)
        item.start.seconds = max(0, start - padding_before)
        item.end.seconds = end + padding_after
        sub_rip_file.append(item)
    return '\n'.join(six.text_type(item) for item in sub_rip_file)



# 根据VTT格式序列化字幕列表，并带有可选的时间填充
def vtt_formatter(subtitles, padding_before=0, padding_after=0):
    """
    Serialize a list of subtitles according to the VTT format, with optional time padding.
    """

    text = srt_formatter(subtitles, padding_before, padding_after)
    text = 'WEBVTT\n\n' + text.replace(',', '.')
    return text
# 将字幕列表序列化为JSON blob
def json_formatter(subtitles):
    """
    Serialize a list of subtitles as a JSON blob.
    """
    subtitle_dicts = [
        {
            'start': start,
            'end': end,
            'content': text,
        }
        for ((start, end), text)
        in subtitles
    ]
    return json.dumps(subtitle_dicts)

# 将字幕列表序列化为换行符分隔的字符串
def raw_formatter(subtitles):
    """
    Serialize a list of subtitles as a newline-delimited string.
    """
    return ' '.join(text for (_rng, text) in subtitles)


FORMATTERS = {
    'srt': srt_formatter,
    'vtt': vtt_formatter,
    'json': json_formatter,
    'raw': raw_formatter,
}


DEFAULT_SUBTITLE_FORMAT = 'srt'
# 设置默认的线程数
DEFAULT_CONCURRENCY = 10
# 这里设置自动翻译
DEFAULT_SRC_LANGUAGE = 'en'
DEFAULT_DST_LANGUAGE = 'en'



# 计算arr的给定百分位数
def percentile(arr, percent):
    """
    Calculate the given percentile of arr.
    """
    arr = sorted(arr)
    index = (len(arr) - 1) * percent
    floor = math.floor(index)
    ceil = math.ceil(index)
    if floor == ceil:
        return arr[int(index)]
    low_value = arr[int(floor)] * (ceil - index)
    high_value = arr[int(ceil)] * (index - floor)
    return low_value + high_value



# 将wav格式转换成无损的flac格式,使用ffmpeg
class FLACConverter(object):  # pylint: disable=too-few-public-methods
    """
    Class for converting a region of an input audio or video file into a FLAC audio file
    """
    # 这里的source_path需要注意

    def __init__(self, source_path, include_before=0.25, include_after=0.25):
        self.source_path = source_path
        self.include_before = include_before
        self.include_after = include_after

# 这里是调用ffmpge
    def __call__(self, region):
        try:
            start, end = region
            start = max(0, start - self.include_before)
            end += self.include_after
            temp = tempfile.NamedTemporaryFile(suffix='.flac', delete=False)

            # ffmpeg_code = os.getcwd()+os.sep+'ffmpeg.exe'
            ffmpeg_code = 'ffmpeg'

            # print(ffmpeg_code)

            command = [ffmpeg_code, "-ss", str(start), "-t", str(end - start),
                       "-y", "-i", self.source_path,
                       "-loglevel", "error", temp.name]
            use_shell = True if os.name == "nt" else False

            try:
                # print('调用os.Popen')
                d11 = subprocess.Popen(
                    command, stdin=subprocess.PIPE, stdout=subprocess.PIPE, shell=use_shell)
                d11.wait()
                d11.kill()
                # print('subrocess执行完毕')
                #stem('ffmpeg -ss '+str(start)+' -t '+str(end - start)+ '-y -i '+self.source_path+ ' -loglevel error '+temp.name)
            except:
                print('使用check_output')
                subprocess.check_output(
                    command, stdin=open(os.devnull), shell=use_shell)
            return temp.read()

        except KeyboardInterrupt:
            return None


# 用于为输入FLAC文件执行语音到文本的类
# 参考 https://github.com/agermanidis/autosub/issues/109
class SpeechRecognizer(object):  # pylint: disable=too-few-public-methods
    """                                                                            
    Class for performing speech-to-text for an input FLAC file.                    
    """

    def __init__(self, language="en", rate=44100, retries=3, api_key=googlekey):
        self.language = language
        self.rate = rate
        self.api_key = api_key
        self.retries = retries

    def __call__(self, data):
        try:
            for _ in range(self.retries):
                url = GOOGLE_SPEECH_API_URL.format(
                    lang=self.language, key=self.api_key)
                headers = {"Content-Type": "audio/x-flac; rate=%d" % self.rate}
                try:
                    resp = requests.post(url, data=data, headers=headers)
                except requests.exceptions.ConnectionError as err:
                    # ip被封,请求过快,超出链接限制
                    continue
                for line in resp.content.decode('utf-8').split("\n"):
                    try:
                        line = json.loads(line)
                        line = line['result'][0]['alternative'][0]['transcript']
                        return line[:1].upper() + line[1:]
                    except IndexError:
                        continue
                    except ValueError as ex:
                        continue

        except KeyboardInterrupt:
            return None

# 用于将句子从一种语言翻译成另一种语言的类
class Translator(object):  # pylint: disable=too-few-public-methods
    """
    Class for translating a sentence from a one language to another.
    """

    def __init__(self, language, api_key, src, dst):
        self.language = language
        self.api_key = api_key
        # self.api_key = 'AIzaSyBOti4mM-6x9WDnZIjIeyEU21OpBXqWBgw'
        self.service = build('translate', 'v2',
                             developerKey=self.api_key)
        self.src = src
        self.dst = dst

    def __call__(self, sentence):
        try:
            if not sentence:
                return None

            result = self.service.translations().list(  # pylint: disable=no-member
                source=self.src,
                target=self.dst,
                q=[sentence]
            ).execute()

            if 'translations' in result and result['translations'] and \
                    'translatedText' in result['translations'][0]:
                return result['translations'][0]['translatedText']

            return None

        except KeyboardInterrupt:
            return None


# 把文件转换成wav文件
def extract_audio(filename, channels=1, rate=16000):
    """
    Extract audio from an input file to a temporary WAV file.
    """
    # 生成一个wav临时文件模型,可进行读写
    temp = tempfile.NamedTemporaryFile(suffix='.wav', delete=False)
    if not os.path.isfile(filename):
        print("The given file does not exist: {}".format(filename))
        # raise Exception("Invalid filepath: {}".format(filename))
    # if not which("ffmpeg"):
        # print("ffmpeg: Executable not found on machine.")
        # raise Exception("Dependency not found: ffmpeg")
    # ffmpeg_code = os.getcwd()+os.sep+'ffmpeg.exe'
    ffmpeg_code ='ffmpeg'

    # print(ffmpeg_code)
    command = [ffmpeg_code, "-y", "-i", filename,
               "-ac", str(channels), "-ar", str(rate),
               "-loglevel", "error", temp.name]
    use_shell = True if os.name == "nt" else False

    try:
        d22 = subprocess.Popen(
            command, stdin=subprocess.PIPE, stdout=subprocess.PIPE, shell=use_shell)
        d22.wait()
        d22.kill()
        # print('process执行成功')
    except:
        subprocess.check_output(
            command, stdin=open(os.devnull), shell=use_shell)
        # os.system('ffmpeg -y -i '+filename+' -ac '+str(channels)+' -ar '+str(rate)+' -loglevel error '+temp.name,shell=use_shell)

        # 计算音频时间,使用第三方库
    tag = TinyTag.get(temp.name)
    return temp.name, rate
    # -----------------------------------


# 使用wave音频库,进行解析和处理
# 对给定的音频文件执行语音活动检测
def find_speech_regions(filename, frame_width=4096, min_region_size=0.5, max_region_size=6):  # pylint: disable=too-many-locals
    """
    Perform voice activity detection on a given audio file.
    """
    # wave的使用文档
    reader = wave.open(filename)
    # 最多可读取n帧音频，并以一串字节的形式进行读取和返回
    sample_width = reader.getsampwidth()
    # 返回采样频率
    rate = reader.getframerate()
    # 返回音频通道数（1单声道，2立体声)
    n_channels = reader.getnchannels()
    # 4096/rate,这是在计算啥子?
    chunk_duration = float(frame_width) / rate
    # getnframes返回音频帧的数量
    n_chunks = int(math.ceil(reader.getnframes()*1.0 / frame_width))
    energies = []

    for _ in range(n_chunks):
        # 最多可读取n帧音频，并以一串字节的形式进行读取和返回
        chunk = reader.readframes(frame_width)
        # 返回片段的均方根，即sqrt(sum(S_i^2)/n)这是衡量音频信号功率的指标。
        energies.append(audioop.rms(chunk, sample_width * n_channels))

    # percentile是定义的函数,进行科学计算
    threshold = percentile(energies, 0.2)

    elapsed_time = 0

    # region是区域,应该是统计时间和进度
    regions = []
    region_start = None

    for energy in energies:
        is_silence = energy <= threshold
        max_exceeded = region_start and elapsed_time - region_start >= max_region_size

        if (max_exceeded or is_silence) and region_start:
            if elapsed_time - region_start >= min_region_size:
                regions.append((region_start, elapsed_time))
                region_start = None

        elif (not region_start) and (not is_silence):
            region_start = elapsed_time
        elapsed_time += chunk_duration
    return regions


# 翻译视频和音频 mp4
def generate_subtitles(
    source_path,  # 此处是输入的文件名
    output=None,  # 此处是输出地址
    concurrency=10,
    src_language='en',
    dst_language='en',
    subtitle_file_format='srt',
    api_key=googlekey,
):


# -------------------------------
    # 这个加个判断,如果是mp3就转换成wav
    print('开始处理视频，调用FFMPEG')
    if os.path.splitext(source_path)[1] !='.wav':
        audio_filename, audio_rate = extract_audio(source_path)
    else:
        audio_filename=source_path
    # 使用wave音频库,进行解析和处理
    regions = find_speech_regions(audio_filename)
    # 多线程处理,注意这里与gui有冲突,需要特殊的函数声明
    pool = multiprocessing.Pool(10)
    # 将wav格式转换成无损的flac格式,使用ffmpeg
    converter = FLACConverter(source_path=audio_filename)
    # 调用googel api 用于为输入FLAC文件执行语音到文本的类
    recognizer = SpeechRecognizer(language=src_language, rate=audio_rate,
                                  api_key=googlekey)
    # print('transcripts')

    # translator = Translator(dst_language,api_key,dst=dst_language,src=src_language)
    transcripts = []

    if regions:
        try:
            # multiprocessing.freeze_support()
            # widgets = ["Converting speech regions to FLAC files: ", Percentage(), ' ', Bar(), ' ',
            #            ETA()]
            # # 展示进度条
            # pbar = ProgressBar(widgets=widgets, maxval=len(regions)).start()
            extracted_regions = []
            # # print('===>for i, extracted_region ')
            for i, extracted_region in enumerate(pool.imap(converter, regions)):
            #     multiprocessing.freeze_support()
                print('extracted_regions.append')
                extracted_regions.append(extracted_region)
            #     pbar.update(i)
            # pbar.finish()

            # widgets = ["Performing speech recognition: ",
            #            Percentage(), ' ', Bar(), ' ', ETA()]
            # pbar = ProgressBar(widgets=widgets, maxval=len(regions)).start()
            # multiprocessing.freeze_support()
            for i, transcript in enumerate(pool.imap(recognizer, extracted_regions)):
                transcripts.append(transcript)
            #     pbar.update(i)
            # pbar.finish()
            print('开始翻译啦啊啊啊')
            if src_language.split("-")[0] != dst_language.split("-")[0]:
                if api_key:
                    google_translate_api_key = api_key
                    translator = Translator(dst_language, google_translate_api_key,
                                            dst=dst_language,
                                            src=src_language)
                    prompt = "Translating from {0} to {1}: ".format(
                        src_language, dst_language)
                    # widgets = [prompt, Percentage(), ' ', Bar(), ' ', ETA()]
                    # pbar = ProgressBar(
                    #     widgets=widgets, maxval=len(regions)).start()
                    translated_transcripts = []
                    for i, transcript in enumerate(pool.imap(translator, transcripts)):
                        translated_transcripts.append(transcript)
                        # pbar.update(i)
                    # pbar.finish()
                    transcripts = translated_transcripts
                else:
                    print(
                        "Error: Subtitle translation requires specified Google Translate API key. "
                        "See --help for further information."
                    )
                    return 1
        except KeyboardInterrupt:
            # pbar.finish()
            pool.terminate()
            pool.join()
            # print("Cancelling transcription")
            print('自定义报错:KeyboardInterrupt')
            # raise
    timed_subtitles = [(r, t) for r, t in zip(regions, transcripts) if t]
    formatter = FORMATTERS.get(subtitle_file_format)
    formatted_subtitles = formatter(timed_subtitles)
    global dest
    dest = output
    if not dest:
        base = os.path.splitext(source_path)[0]
        dest = "{base}.{format}".format(base=base, format=subtitle_file_format)
    with open(dest, 'wb') as output_file:
        output_file.write(formatted_subtitles.encode("utf-8"))
    os.remove(audio_filename)
    return dest

# 获取桌面目录

# def get_desktop():
#     key = winreg.OpenKey(winreg.HKEY_CURRENT_USER,
#                          r'Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders')
#     return winreg.QueryValueEx(key, "Desktop")[0]


# 这是免费调用谷歌的函数,需要研究调用的频率
def googletrans(gotext):
    # translator = Translator()
    translator = tr(service_urls=[
        'translate.google.cn'
        #   'translate.google.com',
        #   'translate.google.co.kr',
    ])
# dest=zh-cn表示输出中文简体
# src en表示源语言为英语 ,auto是自动识别
    gotranstxt = translator.translate(gotext, dest='zh-cn', src='en')
    return gotranstxt.text
# .text是翻译出来的结果
# print(gotrans.text)




# 对单个srt字符串开始翻译
def translate_srt(fold_name_srt):
    # try:
    with open(fold_name_srt, 'r', encoding='UTF-8') as f1:
        srt2 = f1.readlines()
        # ----------------------
        global srtlen
        srtlen = str(len(srt2))
        # len(srt2)字幕文件的字符数

        print('👿字幕数据读取成功,正在解析.......')
        print('读取字符文件内容===>'+str(srtlen)+'个字符数')

        # --------------------------
        # global transfilename
        # transfilename=fold_name_srt
        
        print('-----------------------')

        
        try:
            # 字幕文件字符数不为0.且第4行为空
            if len(srt2) != 0:
                # 如果第4行有汉语
                if len(srt2[3]) == 1:
                    with open(fold_name_srt, 'w+', encoding='utf-8') as f2:
                        for inx, val in enumerate(srt2):
                            q = val
                            try:
                                # if True:
                                if int(inx+1) > 2 and int(inx+2) % 4 == 0:
                                    # 使用自然语言解析接口,免费
                                    res=textTrans(q)
                                    # -------------------------------------------------
                                    # 使用谷歌免费翻译,一定要设置频率
                                    # res = googletrans(q)
                                    # --------------------------------------------


                                    print(res)
                                    print(val)
                                    f2.writelines(res+'\n'+val+'\n')
                                    # 设置0.5秒翻译一句话
                                    # time.sleep(0.5)
                                else:
                                    f2.writelines(q)
                            except:
                                print('请注意频率,防止封禁ip==>翻译出现异常,也可检查网络')
                    print('--------------------------')
                    print('☕ 字幕翻译结束')


                else:
                    print('字幕文件为双语字幕')
                    print('=======>>>>>>>')
            else:
                print('读取srt英语字幕文件为空,请检查')
                print('=======>>>>>>>')

        except:
            print('读取字幕异常,请检查文件名是否含有特殊字符')



# def translate_file(fold_name2):
#     splname2 = os.path.splitext(fold_name2)
#     # 判断是不是字幕文件
#     print('splname2[1]==>'+splname2[1])
#     if '.srt' == splname2[1]:
#             # 用百度api翻译成双语
#         print('文件名是:'+fold_name2)
#         # print('srt字幕文件==>双语字幕~')
#         translate_srt(fold_name2)
#     elif '.mp4' == splname2[1]:
#         # print('单个视频文件,开始分析')
#         # 文件不能过大，否则会翻译失败
#         if googlekey != '':

#             print('单视频文件,正在用AI翻译')
#             mp4name_srt = splname2[0]+str('.srt')
#             print(mp4name_srt)
#             # ---------------------------
#             generate_subtitles(fold_name2)
#             srt_sigal = splname2[0]
#             translate_srt(splname2[0]+str('.srt'))
#         else:
#             print('请在目录中的key.txt文件中,添加自己的google api key')
#     else:
#         print('该文件类型暂不做处理:'+splname2[1])

def translate_file(fold_name2):
    splname2 = os.path.splitext(fold_name2)
    generate_subtitles(fold_name2)
    srt_sigal = splname2[0]
    translate_srt(splname2[0]+str('.srt'))


if __name__ == "__main__":
    filenameg=input('filenameg==>:')
    translate_file(filenameg)

# filenameg=input('filenameg==>:')
# translate_file(filenameg)